练习说明
这套练习围绕两个小章节的重点:6.3 子查询 与 6.4 集合运算查询。题目按从易到难安排,先写基础题,再写综合题。若某题写完后不确定是否正确,可以先执行,再观察结果是否符合题意。
一、上机前先导入模拟数据
先执行下面这一段建表与插入数据的 SQL。后面的练习都默认基于这组数据完成。
DROP TABLE IF EXISTS tc;
DROP TABLE IF EXISTS sc;
DROP TABLE IF EXISTS t;
DROP TABLE IF EXISTS c;
DROP TABLE IF EXISTS s;
CREATE TABLE s (
sno VARCHAR(10) PRIMARY KEY,
sn VARCHAR(20) NOT NULL,
age INT,
maj VARCHAR(20)
);
CREATE TABLE c (
cno VARCHAR(10) PRIMARY KEY,
cn VARCHAR(30) NOT NULL,
ct INT
);
CREATE TABLE t (
tno VARCHAR(10) PRIMARY KEY,
tn VARCHAR(20) NOT NULL,
prof VARCHAR(20),
maj VARCHAR(20),
dept VARCHAR(30),
sal INT
);
CREATE TABLE sc (
sno VARCHAR(10),
cno VARCHAR(10),
score INT
);
CREATE TABLE tc (
tno VARCHAR(10),
cno VARCHAR(10),
tcdate DATE
);
INSERT INTO s VALUES
('s1','张三',18,'计算机'),
('s2','赵琳琳',19,'数学'),
('s3','王敏',20,'计算机'),
('s4','陈晨',21,'英语'),
('s5','李雪',18,'数学'),
('s6','周楠',22,'计算机');
INSERT INTO c VALUES
('c1','程序设计基础',64),
('c2','数据库原理',48),
('c3','高等数学',56),
('c4','Web前端开发',64),
('c5','大学英语',32);
INSERT INTO t VALUES
('t1','顾伟','副教授','计算机','计算机学院',5200),
('t2','李明','讲师','数学','数学学院',5600),
('t3','王华','教授','计算机','计算机学院',6800),
('t4','刘芳','讲师','英语','外国语学院',7000),
('t5','周强','副教授','计算机','计算机学院',6100),
('t6','陈刚','副教授','化学','化学学院',6300);
INSERT INTO sc VALUES
('s1','c1',86),
('s1','c2',90),
('s2','c1',88),
('s2','c2',92),
('s3','c3',85),
('s3','c1',79),
('s4','c2',69),
('s4','c5',80),
('s5','c3',91),
('s5','c2',84),
('s6','c1',95),
('s6','c4',89);
INSERT INTO tc VALUES
('t1','c1','2024-09-01'),
('t1','c2','2024-09-01'),
('t2','c3','2024-09-02'),
('t3','c1','2025-02-20'),
('t4','c5','2024-09-05'),
('t5','c4','2024-09-10');
导入后建议先自检:可以执行
SELECT * FROM s;、SELECT * FROM c;、SELECT * FROM sc; 看看数据是否已经成功写入。这组数据里包含哪些表
| 表名 | 作用 | 关键字段 |
|---|---|---|
| s | 学生表 | sno, sn, age, maj |
| c | 课程表 | cno, cn, ct |
| t | 教师表 | tno, tn, maj, sal |
| sc | 选课表 | sno, cno, score |
| tc | 授课表 | tno, cno, tcdate |
二、必做练习题
1
单值子查询:比赵琳琳年龄大的学生
6 分钟
要求:查询比学生“赵琳琳”年龄大的学号、姓名和年龄。
提示:
- 先想清楚:题目里真正要拿来比较的值是什么。
- 子查询应该先从学生表中查出“赵琳琳”的年龄。
- 外层再使用 > 进行比较。
2
多值子查询:查询 s2 选修的课程信息
7 分钟
要求:查询学号为 s2 的学生选修的课程号、课程名和课时。
提示:
- 先从 sc 表中找到 s2 对应的一组课程号。
- 再去课程表 c 中把这些课程号对应的课程名与课时取出来。
- 本题建议使用 IN。
3
多值子查询:比计算机专业所有教师工资都高
8 分钟
要求:查询其他专业中,比“计算机”专业所有教师工资都高的教师号、姓名、专业和工资。
提示:
- “比所有教师都高”对应的是 ALL。
- 也可以先想它与 MAX 的关系。
- 别忘记排除 maj = 计算机 的教师。
4
相关子查询:查询选修 c1 的学生
7 分钟
要求:使用相关子查询,查询选修了课程号为 c1 的学号和姓名。
提示:
- 外层表是学生表 s。
- 内层表是选课表 sc。
- 关键是把父查询当前行中的 s.sno 带入子查询。
5
NOT EXISTS:查询没有选修 c1 的学生
7 分钟
要求:使用 NOT EXISTS,查询没有选修课程号为 c1 的学号和姓名。
提示:
- 本题与上一题思路接近,只是判断方向相反。
- EXISTS / NOT EXISTS 关心的是有没有记录,而不是返回什么具体值。
6
EXISTS:查询 t1 教授的课程信息
6 分钟
要求:使用 EXISTS,查询教师号为 t1 的教师讲授的课程号、课程名和课时。
提示:
- 最终要输出课程号、课程名、课时,所以外层表应选课程表 c。
- 子查询用 tc 表判断当前课程是否由 t1 讲授。
7
UNION:合并两个专业的学生信息
5 分钟
要求:查询“计算机”专业学生的学号、姓名、专业,再查询“数学”专业学生的学号、姓名、专业,并用 UNION 合并结果。
提示:
- 两边 SELECT 返回的列数和顺序必须一致。
- 本题是把两个结果上下合并,不是连接表。
8
UNION:合并两门课程的统计结果
8 分钟
要求:分别统计 c1 和 c2 的总分、平均分,并用 UNION 合并成一个结果集。结果列名要求为:课程号、总分、平均分。
提示:
- 每一边都要先 GROUP BY cno。
- 两边返回列结构必须完全对应。
- 建议给字段加别名。
9
UNION 去重观察题
7 分钟
要求:查询“计算机”专业学生的学号和姓名,再查询年龄大于等于 20 岁学生的学号和姓名,使用 UNION 合并,并观察结果中是否有重复行。
提示:
- 先写出两个 SELECT,再用 UNION 连接。
- 重点观察同时满足两个条件的学生,最终会不会出现两次。
10
综合题:子查询 + UNION
9 分钟
要求:先查询“没有选修 c1 课程”的学生的学号、姓名、专业;再查询“英语专业”的学生的学号、姓名、专业;最后用 UNION 合并成一个结果集。
提示:
- 前半部分可以使用 NOT EXISTS,也可以使用 NOT IN。
- 后半部分是普通条件筛选。
- 注意两边列结构要一致,且 UNION 会自动去重。
四、完成检查
写完后可以按下面顺序快速自检:
| 检查点 | 说明 |
|---|---|
| 子查询方向对不对 | 先问自己:内层是在查一个值,还是一组值,还是只判断有没有记录。 |
| UNION 两边结构是否一致 | 列数、列顺序、列含义尽量一致,否则容易报错或结果混乱。 |
| 结果是否符合题意 | 不要只看“能运行”,还要看返回的记录是不是题目真正要的。 |
| 是否误把 UNION 写成 JOIN | 合并结果用 UNION;跨表按字段关联用 JOIN。 |
提醒:题目页不包含参考答案。若需要核对 SQL 与结果,请打开单独的答案详解页。